package com.hucsmn.stumansys.utils;

import com.hucsmn.stumansys.entity.Admin;
import com.hucsmn.stumansys.entity.Student;

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 表单元素解析验证工具类。
 * @author hucsmn
 */
public class ConvertUtils {
    private static final Pattern REGEX_ADMIN_NAME = Pattern.compile("^\\w{1,32}$");
    private static final Pattern REGEX_CRYPT = Pattern.compile("^[0-9A-F]{64}$", Pattern.CASE_INSENSITIVE);
    private static final Pattern REGEX_CARD = Pattern.compile("^[0-9]{1,24}$");
    private static final Pattern REGEX_STUDENT_NAME = Pattern.compile("^\\p{Alpha}{1,8}$", Pattern.UNICODE_CHARACTER_CLASS);
    private static final Pattern REGEX_EMAIL = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);

    private static final Pattern SEPARATOR = Pattern.compile("\\s*,\\s*");
    private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public static boolean validateDate(String literal) {
        if (literal == null) {
            return false;
        }

        try {
            FORMAT.parse(literal);
            return true;
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    public static boolean validateAdmin(Admin admin) {
        if (admin == null || admin.getName() == null || admin.getCrypt() == null) {
            return false;
        }
        return REGEX_ADMIN_NAME.matcher(admin.getName()).matches() &&
                REGEX_CRYPT.matcher(admin.getCrypt()).matches();
    }

    public static boolean validateStudent(Student student) {
        if (student == null || student.getCard() == null || student.getName() == null) {
            return false;
        }
        if (!REGEX_CARD.matcher(student.getCard()).matches()) {
            return false;
        }
        if (!REGEX_STUDENT_NAME.matcher(student.getName()).matches()) {
            return false;
        }
        if (student.getBirth() != null && !validateDate(student.getBirth())) {
            return false;
        }
        return student.getEmail() == null || REGEX_EMAIL.matcher(student.getEmail()).matches();
    }

    public static String normalizeText(String param) {
        if (param == null) {
            return null;
        }

        param = param.trim();
        if (param.isEmpty()) {
            return null;
        }
        return param;
    }

    public static int[] parseIdList(String list) {
        if (list == null) {
            return new int[0];
        }
        return Arrays.stream(SEPARATOR.split(list))
                .mapToInt(literal -> {
                    try {
                        return Integer.parseInt(literal);
                    } catch (NumberFormatException e) {
                        return -1;
                    }
                })
                .filter(id -> id >= 0)
                .toArray();
    }

    public static int[] parseIdLists(String[] idLists) {
        if (idLists == null) {
            return new int[0];
        }
        return Arrays.stream(idLists)
                .map(ConvertUtils::parseIdList)
                .flatMapToInt(Arrays::stream)
                .toArray();
    }

    public static String idListToString(int[] ids) {
        return Arrays.stream(ids).mapToObj(String::valueOf).collect(Collectors.joining(","));
    }

    public static Optional<Integer> parseId(String id) {
        if (id == null) {
            return Optional.empty();
        }
        try {
            int number = Integer.parseInt(id);
            if (number >= 0) {
                return Optional.of(number);
            }
        } catch (NumberFormatException e) {
            return Optional.empty();
        }
        return Optional.empty();
    }

    public static Optional<Boolean> parseFlag(String flag) {
        if (flag == null) {
            return Optional.empty();
        }
        if (flag.equalsIgnoreCase("true") || flag.equalsIgnoreCase("t") ||
                flag.equalsIgnoreCase("yes") || flag.equalsIgnoreCase("y")) {
            return Optional.of(true);
        }
        if (flag.equalsIgnoreCase("false") || flag.equalsIgnoreCase("f") ||
                flag.equalsIgnoreCase("no") || flag.equalsIgnoreCase("n")) {
            return Optional.of(false);
        }
        return Optional.empty();
    }
}
